package com.blog.interceptors;


import com.blog.constant.RedisConstant;
import com.blog.properties.JwtProperties;
import com.blog.util.JwtUtil;
import com.blog.util.ThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

@Component
@Slf4j
public class JwtTokenInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     *  将登入与注册之外的请求拦截下来，进行token验证，并把token中的用户数据存入线程中
     * @param request
     * @param response
     * @param handler
     * @return
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 获取请求头中的平台标识
        String platform = request.getHeader("platform");
        
        // 如果是用户平台请求,只对特定接口要求token
        if ("user".equals(platform)) {
            String requestPath = request.getRequestURI();
            // 只有这些接口需要用户token
            if (requestPath.startsWith("/review/add") || 
                requestPath.startsWith("/user/info") ||
                requestPath.startsWith("/user/updatePwd") ||
                requestPath.startsWith("/user/updateAvatar") ||
                requestPath.startsWith("/upload")) {
                log.info("用户请求路径：{}", requestPath);
                return checkToken(request, response, JwtProperties.ROLE_USER);
            }
            return true;
        }
        
        // 如果是管理员平台请求,所有接口都需要token
        else if ("admin".equals(platform)) {
            return checkToken(request, response, JwtProperties.ROLE_ADMIN);
        }
        
        return true;
    }

    // 验证token的方法
    private boolean checkToken(HttpServletRequest request, HttpServletResponse response, String requiredRole) {
        String token = request.getHeader("Authorization");
        log.info("token：{}", token);
        if (token == null) {
            log.info("请求头中不存在token");
            response.setStatus(401);
            return false;
        }

        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            String role = (String) claims.get("role");
            log.info("验证前的role：{}、requiredRole：{}", role, requiredRole);
            // 验证角色
            if (!requiredRole.equals(role)) {
                log.info("role不匹配");
                response.setStatus(403);
                return false;
            }

            // 验证Redis中的token
            String redisKey = JwtProperties.ROLE_ADMIN.equals(role) ? 
                RedisConstant.ADMIN_TOKEN_KEY : RedisConstant.USER_TOKEN_KEY;
            String redisToken = (String) redisTemplate.opsForValue().get(redisKey);
            
            if (redisToken == null || !token.equals(redisToken)) {
                log.info("redis中不存在token或token不对");
                response.setStatus(401);
                return false;
            }

            // 将用户信息存入ThreadLocal
            ThreadLocalUtil.set(claims);
            return true;
        } catch (Exception e) {
            log.info("校验不通过");
            response.setStatus(401);
            return false;
        }
    }

    /**
     * 再请求完毕后关闭线程，防止资源消耗
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        //关闭线程，防止资源消耗
        ThreadLocalUtil.remove();
    }

}
